﻿using UnityEngine;
using UnityEngine.Rendering;
using UnityEngine.Rendering.Universal;

namespace KunURP
{

    public class RadialBlur : ScriptableRendererFeature
    {
        [System.Serializable]
        public class Setting
        {
            public RenderPassEvent passEvent = RenderPassEvent.AfterRenderingTransparents;//默认插到透明完成后
            public Material material;
            [Range(0, 1)]
            public float centerX = 0.5f;
            [Range(0, 1)]
            public float centerY = 0.5f;
            [Range(1, 10)]
            public int loopCount = 5;
            [Range(1, 8)]
            public float blurRadius = 3.0f;
            [Range(0, 1)]
            public float instensity = 0.5f;
        }

        public Setting m_Setting = new Setting();

        class CustomRenderPass : ScriptableRenderPass
        {
            public const int MaxLevel = 16;

            public Material material;
            public float centerX = 0.5f;
            public float centerY = 0.5f;
            public int loopCount;
            public float blurRadius;
            public float instensity = 0.5f;

            FilterMode passFilterMode{ get;set;}//图像的模式
            RenderTargetIdentifier passSource{get;set;}//源图像,目标图像
            string passTag;

            static class ShaderIDs
            {
                internal static readonly int SourceTex = Shader.PropertyToID("_SourceTex");
                internal static readonly int BlurTex = Shader.PropertyToID("_BlurTex");
                internal static readonly int BlurRadius = Shader.PropertyToID("_BlurRadius");
                internal static readonly int CenterX = Shader.PropertyToID("_CenterX");
                internal static readonly int CenterY = Shader.PropertyToID("_CenterY");
                internal static readonly int LoopCount = Shader.PropertyToID("_LoopCount");
                internal static readonly int Instensity = Shader.PropertyToID("_Instensity");
            }

            public CustomRenderPass(string tag)
            {
                this.passTag = tag;
            }

            public void Setup(RenderTargetIdentifier passSource)
            {
                this.passSource = passSource;
            }
            
            public override void Execute(ScriptableRenderContext context, ref RenderingData renderingData)
            {
                CommandBuffer cmd = CommandBufferPool.Get(this.passTag);
                RenderTextureDescriptor opaqueDesc = renderingData.cameraData.cameraTargetDescriptor;
                cmd.GetTemporaryRT(ShaderIDs.BlurTex, opaqueDesc.width, opaqueDesc.height, 0, this.passFilterMode);
                cmd.GetTemporaryRT(ShaderIDs.SourceTex, opaqueDesc.width, opaqueDesc.height, 0, this.passFilterMode);
                material.SetInt(ShaderIDs.LoopCount, this.loopCount);
                material.SetFloat(ShaderIDs.BlurRadius, this.blurRadius);
                material.SetFloat(ShaderIDs.Instensity, this.instensity);
                material.SetFloat(ShaderIDs.CenterX, this.centerX);
                material.SetFloat(ShaderIDs.CenterY, this.centerY);
                RenderTargetIdentifier blurTex = new RenderTargetIdentifier(ShaderIDs.BlurTex);
                RenderTargetIdentifier sourceTex = new RenderTargetIdentifier(ShaderIDs.SourceTex);
                cmd.Blit(this.passSource, sourceTex);
                cmd.Blit(this.passSource, blurTex, this.material, 0);
                cmd.Blit(blurTex, this.passSource, this.material, 1);


                cmd.ReleaseTemporaryRT(ShaderIDs.BlurTex);
                context.ExecuteCommandBuffer(cmd);
                CommandBufferPool.Release(cmd);
            }

        }

        CustomRenderPass m_ScriptablePass;

        public override void Create()
        {
            this.m_ScriptablePass = new CustomRenderPass(name);
            this.m_ScriptablePass.renderPassEvent = this.m_Setting.passEvent;
            this.m_ScriptablePass.material = this.m_Setting.material;
            this.m_ScriptablePass.centerX = this.m_Setting.centerX;
            this.m_ScriptablePass.centerY = this.m_Setting.centerY;
            this.m_ScriptablePass.loopCount = this.m_Setting.loopCount;
            this.m_ScriptablePass.instensity = this.m_Setting.instensity;
            this.m_ScriptablePass.blurRadius = this.m_Setting.blurRadius;
        }

        // Here you can inject one or multiple render passes in the renderer.
        // This method is called when setting up the renderer once per-camera.
        public override void AddRenderPasses(ScriptableRenderer renderer, ref RenderingData renderingData)
        {
            if (this.m_Setting.material != null)
            {
                this.m_ScriptablePass.Setup(renderer.cameraColorTarget);
                renderer.EnqueuePass(this.m_ScriptablePass);
            }
        }
    }

}